﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Workbench.Models;
using Workbench.Operations;
using Workbench.Persistance;

namespace WorkbenchTests.Operations
{
    [TestClass]
    public class LemmatizerOperationsTests
    {
        [TestInitialize]
        public void Setup()
        {
            TestUtility.CreateAndInitializeTempDatabase();
            TestUtility.AddDefaultPOSTypes();
        }

        [TestMethod]
        public void LemmatizerOperations_can_get_sentence_from_word()
        {
            string sentence1 = "This is Sentence1.";
            string sentence2 = "This is Sentence2.";
            string paragraph = string.Join(" ", sentence1, sentence2);
            
            var file = TestUtility.CreateProcessedFile(paragraph);

            var words = LemmatizerOperations.GetWords(file);
            Assert.AreEqual(sentence1, LemmatizerOperations.GetSentence(words[0]));
            Assert.AreEqual(sentence1, LemmatizerOperations.GetSentence(words[1]));
            Assert.AreEqual(sentence1, LemmatizerOperations.GetSentence(words[2]));
            Assert.AreEqual(sentence2, LemmatizerOperations.GetSentence(words[3]));
            Assert.AreEqual(sentence2, LemmatizerOperations.GetSentence(words[4]));
            Assert.AreEqual(sentence2, LemmatizerOperations.GetSentence(words[5]));
        }

        [TestMethod]
        public void LemmatizerOperations_can_persist_base_form()
        {
            string text = "This is Sentence1.";

            var file = TestUtility.CreateProcessedFile(text);
            var words = LemmatizerOperations.GetWords(file);
            string baseFormContent = "sentence";

            for (int i = 0; i < 2; i++)
            {
                LemmatizerOperations.UpdateBaseFormForWords(baseFormContent, words[2]);

                var persistedBaseFormId = words[2].BaseFormId;
                Assert.AreNotEqual(0, persistedBaseFormId);

                words = LemmatizerOperations.GetWords(file);
                var word = words.Where(x => string.Compare("Sentence1", x.GetContent(), false) == 0).Single();
                Assert.AreEqual(persistedBaseFormId, word.BaseFormId);
                Assert.AreEqual(persistedBaseFormId, word.BaseForm.RowId);
                Assert.AreEqual(baseFormContent, word.BaseForm.Content);
            }
        }

        [TestMethod]
        public void LemmatizerOperations_suggests_correctly()
        {
            string text = "word wind.";

            var file = TestUtility.CreateProcessedFile(text);
            var words = LemmatizerOperations.GetWords(file);
            LemmatizerOperations.UpdateBaseFormForWords("word", words[0]);
            LemmatizerOperations.UpdateBaseFormForWords("wind", words[1]);

            var suggestions = LemmatizerOperations.GetBaseFormSuggestions("w");
            Assert.AreEqual(2, suggestions.Count);
            Assert.AreEqual("wind", suggestions[0].Content);
            Assert.AreEqual("word", suggestions[1].Content);
        }

        [TestMethod]
        public void LemmatizerOperations_udf_pos_types_add_remove_pos_type_to_word()
        {
            var file = TestUtility.CreateProcessedFile("Орачът оре.");
            var words = LemmatizerOperations.GetWords(file);
            var posTypes = ProjectOperations.GetPOSTypes();
            var noun = posTypes.Where(x => x.Name == "Noun").Single();

            POSTaggerOperations.AddPosTypeToWords(noun, words);
            Assert.AreEqual(2, words.Count);
            Assert.AreEqual(1, words[0].POSTypes.Count);
            Assert.AreEqual(noun, words[0].POSTypes.Single());
            Assert.AreEqual(1, words[1].POSTypes.Count);
            Assert.AreEqual(noun, words[1].POSTypes.Single());

            POSTaggerOperations.RemovePosTypeFromWords(noun, new List<WordModel> { words[0] });
            Assert.AreEqual(0, words[0].POSTypes.Count);
            Assert.AreEqual(1, words[1].POSTypes.Count);
            Assert.AreEqual(noun, words[1].POSTypes.Single());
        }

        [TestMethod]
        public void LemmatizerOperations_udf_pos_types_add_remove_pos_type_to_word_in_file()
        {
            var file = TestUtility.CreateProcessedFile("this word this is repeated this times.");
            var file2 = TestUtility.CreateProcessedFile("this word this is repeated this times.");
            var words = LemmatizerOperations.GetWords(file);
            var posTypes = ProjectOperations.GetPOSTypes();
            var noun = posTypes.Where(x => x.Name == "Noun").Single();
            var thisWord = words.Where(x => x.UniqueWord.Content == "this").First();

            POSTaggerOperations.AddPosTypeToWordInFile(noun.RowId, thisWord.UniqueWordId, file.RowId);

            words = LemmatizerOperations.GetWords(file);
            Assert.IsTrue(words.Where(x => x.UniqueWord.Content == "this").All(x => x.POSTypes.Single().Name == "Noun"));
            
            words = LemmatizerOperations.GetWords(file2);
            Assert.IsTrue(words.Where(x => x.UniqueWord.Content == "this").All(x => x.POSTypes.Count == 0));

            POSTaggerOperations.RemovePosTypeFromWordInFile(noun.RowId, thisWord.UniqueWordId, file.RowId);

            words = LemmatizerOperations.GetWords(file);
            words.AddRange(LemmatizerOperations.GetWords(file2));
            Assert.IsTrue(words.Where(x => x.UniqueWord.Content == "this").All(x => x.POSTypes.Count == 0));
        }

        [TestMethod]
        public void LemmatizerOperations_udf_pos_types_add_remove_pos_type_to_word_in_all_files()
        {
            var file = TestUtility.CreateProcessedFile("this word this is repeated this times.");
            var file2 = TestUtility.CreateProcessedFile("this word this is repeated this times.");
            var words = LemmatizerOperations.GetWords(file);
            var posTypes = ProjectOperations.GetPOSTypes();
            var noun = posTypes.Where(x => x.Name == "Noun").Single();
            var thisWord = words.Where(x => x.UniqueWord.Content == "this").First();

            POSTaggerOperations.AddPosTypeToWordInAllFiles(noun.RowId, thisWord.UniqueWordId);

            words = LemmatizerOperations.GetWords(file);
            words.AddRange(LemmatizerOperations.GetWords(file2));
            Assert.IsTrue(words.Where(x => x.UniqueWord.Content == "this").All(x => x.POSTypes.Single().Name == "Noun"));

            POSTaggerOperations.RemovePosTypeFromWordInAllFiles(noun.RowId, thisWord.UniqueWordId);

            words = LemmatizerOperations.GetWords(file);
            words.AddRange(LemmatizerOperations.GetWords(file2));
            Assert.IsTrue(words.Where(x => x.UniqueWord.Content == "this").All(x => x.POSTypes.Count == 0));
        }

        [TestMethod]
        public void LemmatizerOperations_udf_pos_types_get_pos_types_for_word()
        {
            var file = TestUtility.CreateProcessedFile("Орачът оре.");
            var words = LemmatizerOperations.GetWords(file);
            var posTypes = ProjectOperations.GetPOSTypes();
            var noun = posTypes.Where(x => x.Name == "Noun").Single();
            var adverb = posTypes.Where(x => x.Name == "Adverb").Single();

            POSTaggerOperations.AddPosTypeToWords(noun, words);
            POSTaggerOperations.AddPosTypeToWords(adverb, words);

            words = LemmatizerOperations.GetWords(file);

            Assert.AreEqual(2, words.Count);
            Assert.AreEqual(2, words[0].POSTypes.Count);
            Assert.AreEqual(2, words[1].POSTypes.Count);

            POSTaggerOperations.RemovePosTypeFromWords(noun, new List<WordModel> { words[0] });
            Assert.AreEqual(1, words[0].POSTypes.Count);
            Assert.AreEqual(2, words[1].POSTypes.Count);
        }

        [TestMethod]
        public void LemmatizerOperations_udf_pos_types_can_add_nested_types()
        {
            var file = TestUtility.CreateProcessedFile("Орачът.");
            var words = LemmatizerOperations.GetWords(file);
            var posTypes = ProjectOperations.GetPOSTypes();
            var noun = posTypes.Where(x => x.Name == "Noun").Single();
            var noun2 = ProjectOperations.AddPOSType("Noun2", noun);
            var adverb = posTypes.Where(x => x.Name == "Adverb").Single();

            POSTaggerOperations.AddPosTypeToWords(noun2, words);
            POSTaggerOperations.AddPosTypeToWords(adverb, words);

            words = LemmatizerOperations.GetWords(file);

            Assert.AreEqual(1, words.Count);
            Assert.AreEqual(2, words[0].POSTypes.Count);
            Assert.IsTrue(words[0].POSTypes.Contains(noun2));
            Assert.IsTrue(words[0].POSTypes.Contains(adverb));
        }
    }
}
